package com.fxf.srb.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fxf.common.exception.Assert;
import com.fxf.common.exception.BusinessException;
import com.fxf.common.result.ResponseEnum;
import com.fxf.srb.core.enums.LendStatusEnum;
import com.fxf.srb.core.enums.TransTypeEnum;
import com.fxf.srb.core.hfb.FormHelper;
import com.fxf.srb.core.hfb.HfbConst;
import com.fxf.srb.core.hfb.RequestHelper;
import com.fxf.srb.core.mapper.LendMapper;
import com.fxf.srb.core.mapper.UserAccountMapper;
import com.fxf.srb.core.mapper.UserInfoMapper;
import com.fxf.srb.core.pojo.bo.TransFlowBO;
import com.fxf.srb.core.pojo.entity.Lend;
import com.fxf.srb.core.pojo.entity.LendItem;
import com.fxf.srb.core.mapper.LendItemMapper;
import com.fxf.srb.core.pojo.entity.UserAccount;
import com.fxf.srb.core.pojo.entity.UserInfo;
import com.fxf.srb.core.pojo.vo.InvestVO;
import com.fxf.srb.core.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fxf.srb.core.util.LendNoUtils;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 标的出借记录表 服务实现类
 * </p>
 *
 * @author fxf
 * @since 2021-05-26
 */
@Service
@Slf4j
public class LendItemServiceImpl extends ServiceImpl<LendItemMapper, LendItem> implements ILendItemService {

    @Resource
    private UserInfoMapper userInfoMapper;
    @Resource
    private LendMapper lendMapper;
    @Resource
    private IUserAccountService userAccountService;
    @Resource
    private UserAccountMapper userAccountMapper;
    @Resource
    private ILendService iLendService;
    @Resource
    private IUserBindService userBindService;
    @Resource
    private ITransFlowService iTransFlowService;


    /**
     * 构建投标自动提交表单
     * @param investVO
     * @return
     */
    @Override
    public String commitInvest(InvestVO investVO) {

        //根据标的id获取标的信息
        Lend lend = lendMapper.selectById(investVO.getLendId());

        //- 标的状态必须为募资中
        Assert.isTrue(lend.getStatus().intValue() == LendStatusEnum.INVEST_RUN.getStatus().intValue(),
                ResponseEnum.LEND_INVEST_ERROR);
        //- 标的不能超卖：(已投金额 + 本次投资金额 )>=标的金额（超卖）
        //本次投资金额加上已投金额
        BigDecimal sum = lend.getInvestAmount().add(new BigDecimal(investVO.getInvestAmount()));
        //判断标的是否超卖
//        if (sum.doubleValue()>= lend.getAmount().doubleValue()){
//            new BusinessException(ResponseEnum.LEND_FULL_SCALE_ERROR);
//        }
        //断言判断
        Assert.isTrue(sum.doubleValue() <= lend.getAmount().doubleValue(),
                ResponseEnum.LEND_FULL_SCALE_ERROR);
        //- 账户可用余额充足 当前用户的余额 >= 当前用户的投资金额（可以投资）
        //查询投资人帐号余额
        BigDecimal userAccount = userAccountService.getAccount(investVO.getInvestUserId());
//        Assert.isTrue(userAccount.doubleValue() >= Double.parseDouble(investVO.getInvestAmount()),
//                ResponseEnum.NOT_SUFFICIENT_FUNDS_ERROR);
        //断言判断当前用户余额是否充足够用
        Assert.isTrue(userAccount.doubleValue() >= new BigDecimal(investVO.getInvestAmount()).doubleValue(),
                ResponseEnum.NOT_SUFFICIENT_FUNDS_ERROR);


        LendItem lendItem = new LendItem();
        lendItem.setInvestUserId(investVO.getInvestUserId());//投资人id
        lendItem.setInvestName(investVO.getInvestName());//投资人名字
        String lendItemNo = LendNoUtils.getLendItemNo();
        lendItem.setLendItemNo(lendItemNo); //投资条目编号（一个Lend对应一个或多个LendItem）
        lendItem.setLendId(investVO.getLendId());//标的标号
        lendItem.setInvestAmount(new BigDecimal(investVO.getInvestAmount()));//投资金额
        lendItem.setLendYearRate(lend.getLendYearRate());//年化利率
        lendItem.setInvestTime(LocalDateTime.now());//投资时间
        lendItem.setLendStartDate(lend.getLendStartDate());//开始日期
        lendItem.setLendEndDate(lend.getLendEndDate());//结束日期
        BigDecimal interestCount = iLendService.getInterestCount(new BigDecimal(
                //投资金额
                investVO.getInvestAmount()),
                //年化利率
                lend.getLendYearRate(),
                //期数
                lend.getPeriod(),
                //还款方式
                lend.getReturnMethod());
        lendItem.setExpectAmount(interestCount);//预期收益
        lendItem.setRealAmount(new BigDecimal(0));//实际收益

        lendItem.setStatus(0);//默认状态：刚刚创建
        baseMapper.insert(lendItem);


        //获取投资人绑定协议号
        String bindCode = userBindService.getBindCodeByUserId(investVO.getInvestUserId());
        //获取借款人绑定协议号
        String lendBindCode = userBindService.getBindCodeByUserId(lend.getUserId());
//        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
//        wrapper.eq("user_id",investVO.getInvestUserId());
//        UserInfo userInfo = userInfoMapper.selectOne(wrapper);


        Map<String, Object> paramMaps = new HashMap<>();
        paramMaps.put("agent_id", HfbConst.AGENT_ID);//商户唯一标识
        paramMaps.put("vote_bind_code",bindCode);//投资人绑定协议号
        paramMaps.put("benefit_bind_code",lendBindCode);//借款人绑定协议号
        paramMaps.put("agent_project_code",lend.getLendNo());//项目编号
        paramMaps.put("agent_project_name",lend.getTitle());//项目名称
        //在资金托管平台上的投资订单的唯一编号，要和lendItemNo保持一致。
        paramMaps.put("agentBillNo", lendItemNo);//订单编号
        paramMaps.put("vote_amt", investVO.getInvestAmount());
        paramMaps.put("vote_prize_amt", "0");
        paramMaps.put("vote_fee_amt", "0");
        paramMaps.put("project_amt", lend.getAmount()); //标的总金额
        paramMaps.put("note", "");
        paramMaps.put("notify_url", HfbConst.INVEST_NOTIFY_URL); //检查常量是否正确
        paramMaps.put("return_url", HfbConst.INVEST_RETURN_URL);
        paramMaps.put("timestamp", RequestHelper.getTimestamp());
        String sign = RequestHelper.getSign(paramMaps);
        paramMaps.put("sign",sign);
        String formStr = FormHelper.buildForm(HfbConst.INVEST_URL, paramMaps);
        return formStr;
    }

    /**
     * 汇付宝异步回调接口，更改投资人账户金额、更新标的信息及添加相关交易流水
     *
     * @param paramMap
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void notify(Map<String, Object> paramMap) {
        log.info("投标成功");
        //获取投资编号
        String agentBillNo = (String)paramMap.get("agentBillNo");
        boolean result = iTransFlowService.isSaveTransFlow(agentBillNo);
        if(result){
            log.warn("幂等性返回");
            return;
        }

        //投资人账户金额更改（剩余金额和冻结金额）
        String bindCode = (String) paramMap.get("vote_bind_code");
        String voteAmt = (String) paramMap.get("vote_amt");
        userAccountMapper.updateAccount(bindCode,new BigDecimal("-" + voteAmt),new BigDecimal(voteAmt));
        //修改投资状态（lend_item表中的status）
        LendItem lendItem = this.getByLendItemNo(agentBillNo);;
        lendItem.setStatus(1);
        baseMapper.updateById(lendItem);
        //更新标的信息（lend表中的投资人数和已投金额）
        Long lendId = lendItem.getLendId();
        Lend lend = lendMapper.selectById(lendId);
        lend.setInvestAmount(new BigDecimal(voteAmt));
        Integer investNum = lend.getInvestNum();
        lend.setInvestNum(investNum++);
        lendMapper.updateById(lend);
        //添加交易流水
        TransFlowBO transFlowBO = new TransFlowBO(
                agentBillNo,bindCode,new BigDecimal(voteAmt),TransTypeEnum.INVEST_LOCK,
                "投资项目编号：" + lend.getLendNo() + "，项目名称：" + lend.getTitle());
        iTransFlowService.saveTransFlow(transFlowBO);
    }

    /**
     * 获取投资信息
     * @param id
     * @param status
     * @return
     */
    @Override
    public List<LendItem> selectByLendId(Long id, Integer status) {
        QueryWrapper<LendItem> wrapper = new QueryWrapper<>();
        wrapper.eq("lend_id",id);
        wrapper.eq("status",status);
        List<LendItem> lendItemList = baseMapper.selectList(wrapper);
        return lendItemList;
    }

    @Override
    public List<LendItem> selectByLendId(Long lendId) {
        QueryWrapper<LendItem> queryWrapper = new QueryWrapper();
        queryWrapper.eq("lend_id", lendId);
        List<LendItem> lendItemList = baseMapper.selectList(queryWrapper);
        return lendItemList;
    }

    /**
     * 根据投资编号查询标的出借记录
     * @param agentBillNo
     * @return
     */
    private LendItem getByLendItemNo(String agentBillNo) {
        QueryWrapper<LendItem> wrapper = new QueryWrapper<>();
        wrapper.eq("lend_item_no",agentBillNo);
        LendItem lendItem = baseMapper.selectOne(wrapper);
        return lendItem;
    }
}
